﻿using System.Linq;

namespace Calculator
{
    public class ExpressionValidator : IExpressionValidator
    {
        private readonly IOperatorHandler operatorHandler;

        public ExpressionValidator(IOperatorHandler operatorHandlerParam)
        {
            operatorHandler = operatorHandlerParam;
        }

        public bool Validate(string expression)
        {
            return
                ValidParentheses(expression) &&
                NoNeighborOperators(expression) &&
                NoInvalidNumberNearParenthes(expression) &&
                NoOtherGarbage(expression);
        }

        private bool ValidParentheses(string expression)
        {
            int n = 0;
            foreach (char c in expression)
            {
                switch (c)
                {
                    case '(':
                        n++;
                        break;
                    case ')':
                        n--;
                        break;
                }
            }

            return n == 0;
        }

        private bool NoNeighborOperators(string expression)
        {
            for (int i = 0; i < expression.Length - 1; i++)
            {
                if (operatorHandler.IsOperator(expression[i]) &&
                    operatorHandler.IsOperator(expression[i+1]))
                {
                    return false;
                }
            }
            return true;
        }

        private bool NoInvalidNumberNearParenthes(string expression)
        {
            for (int i = 0; i < expression.Length - 1; i++)
            {
                if (
                    (char.IsNumber(expression[i]) && expression[i+1] == '(') ||
                    (expression[i] == ')' && char.IsNumber(expression[i+1])))
                {
                    return false;
                }
            }
            return true;
        }

        private bool NoOtherGarbage(string expression)
        {
            return expression.All(c => 
                operatorHandler.IsOperator(c) || 
                char.IsNumber(c) || 
                c == '(' || c == ')');
        }
    }
}